﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Configuration;
using Marbles.Core.Encryption;
using System.Configuration;
using System.Web;
using System.Net;
using System.Reflection;
using Marbles.Core.Handlers;
using System.IO;
using System.Xml;
using System.Xml.XPath;

namespace Marbles.Core.Settings
{
    public static class SettingsManager
    {

        public static DataConnectionSettings Connection
        {
            get { return new DataConnectionSettings(); }
            set { DataConnectionSettings.UpdateDataConnectionSettings(value); }
        }

        public static AspNetHostingPermissionLevel TrustLevel
        {
            get { return GetTrustLevel(); }
        }


        public static MailSettings MailSettings
        {
            get { return new MailSettings(); }
            set { MailSettings.UpdateMailSettings(value); }
        }

        public static string ResourceDirectoryRoot
        {
            get { return GetValue("ResourceDirectoryRoot"); }
            set { SetValue("ResourceDirectoryRoot", value); }
        }

        public static string UserFormMailAddress
        {
            get { return GetEncryptedValue("UserFormMailAddress"); }
            set { SetEncryptedValue("UserFormMailAddress", value); }
        }

        public static string ModuleInstallationDirectory
        {
            get { return GetValue("ModuleInstallationDirectory"); }
            set { SetValue("ModuleInstallationDirectory", value); }
        }

        public static string RunTimeErrorMailAddress
        {
            get { return GetEncryptedValue("RunTimeErrorMailAddress"); }
            set { SetEncryptedValue("RunTimeErrorMailAddress", value); }
        }

        public static bool EnableRunTimeErrorMailing
        {
            get
            {
                bool value = false;
                if (!bool.TryParse(GetValue("EnableRunTimeErrorMailing"), out value)) { value = false; }
                return value;
            }
            set { SetValue("EnableRunTimeErrorMailing", value.ToString()); }
        }

        public static bool EnableWysiwygEditing
        {
            get
            {
                bool value = true;
                if (!bool.TryParse(GetValue("EnableWysiwygEditing"), out value)) { value = true; }
                return value;
            }
            set { SetValue("EnableWysiwygEditing", value.ToString()); }
        }

        public static bool ShowFullDebugInfoToClient
        {
            get
            {
                bool value = false;
                if (!bool.TryParse(GetValue("ShowFullDebugInfoToClient"), out value)) { value = false; }
                return value;
            }
            set { SetValue("ShowFullDebugInfoToClient", value.ToString()); }
        }

        public static bool DeveloperMode
        {
            get
            {
                bool value = false;
                if (!bool.TryParse(GetValue("DeveloperMode"), out value)) { value = false; }
                return value;
            }
            set { SetValue("DeveloperMode", value.ToString()); }
        }

        public static string AssetCompression
        {
            get { return GetValue("AssetCompression"); }
            set { SetValue("AssetCompression", value); }
        }

        public static string AuthenticationProvider
        {
            get { return GetValue("AuthenticationProvider"); }
            set { SetValue("AuthenticationProvider", value); }
        }

        public static string TemplateFolder
        {
            get { return GetValue("TemplateFolder"); }
            set { SetValue("TemplateFolder", value); }
        }

        public static string PageCompression
        {
            get { return GetValue("PageCompression"); }
            set { SetValue("PageCompression", value); }
        }

        public static string PageStatePersister
        {
            get { return GetValue("PageStatePersister"); }
            set { SetValue("PageStatePersister", value); }
        }

        public static string GoogleAPIKey
        {
            get { return Marbles.Resources.ResourceHandler.GetGoogleAPIKey(); }
        }

        private static string WebConfigFile
        {
            get { return Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath, "web.config"); }
        }

        private static string GetEncryptedValue(string key)
        {
            string value = GetValue(key);
            return EncryptionProvider.Decode1(value, EncryptionProviderType.TripleDES);
        }

        private static void SetEncryptedValue(string key, string value)
        {
            SetValue(key, EncryptionProvider.Encode1(value, EncryptionProviderType.TripleDES));
        }

        private static string GetValue(string key)
        {
            string value = string.Empty;
            string filename = HttpContext.Current.Server.MapPath(HttpContext.Current.Request.ApplicationPath + "/web.config");
            StreamReader sr = new StreamReader(filename);
            XPathDocument doc = new System.Xml.XPath.XPathDocument(sr);
            XPathNavigator nav = doc.CreateNavigator();
            XPathNodeIterator result = nav.Select("//configuration/appSettings/add[@key='" + key + "']");
            if (result.Count > 0)
            {
                result.MoveNext();
                value = result.Current.GetAttribute("value", "");
            }

            sr.Close();
            return value;
        }

        private static void SetValue(string key, string value)
        {
            XmlDocument xmlDoc = new XmlDocument();
            string filename = HttpContext.Current.Server.MapPath(HttpContext.Current.Request.ApplicationPath + "/web.config");
            xmlDoc.Load(filename);
            XmlElement root = xmlDoc.DocumentElement;
            XmlNode node = root.SelectSingleNode("//configuration/appSettings/add[@key='" + key + "']");

            if (node != null)
            {
                node.Attributes["value"].Value = value;
            }
            else
            {
                node = xmlDoc.CreateElement("add");
                XmlAttribute nKey = xmlDoc.CreateAttribute("key");
                nKey.Value = key;
                XmlAttribute nValue = xmlDoc.CreateAttribute("value");
                nValue.Value = value;
                node.Attributes.Append(nKey);
                node.Attributes.Append(nValue);
                root.SelectSingleNode("//configuration/appSettings").AppendChild(node);
            }

            xmlDoc.Save(filename);
        }

        public static bool IsHttpHandlerRegistered(Type type)
        {
            HttpHandlersSection sysweb = WebConfigurationManager.GetSection("system.web/httpHandlers") as HttpHandlersSection;

            for (int i = 0; i < sysweb.Handlers.Count; i++)
            {
                if (sysweb.Handlers[i].Type == type.AssemblyQualifiedName)
                {
                    return true;
                }
            }

            return false;
        }

        public static bool RegisterHttpModule(Marbles.Core.Handlers.IHttpModuleBase module)
        {
            HttpModulesSection sysweb = WebConfigurationManager.GetSection("system.web/httpModules") as HttpModulesSection;
            string AssemblyQualifiedName = module.GetType().AssemblyQualifiedName;

            for (int i = 0; i < sysweb.Modules.Count; i++)
            {
                if (sysweb.Modules[i].Type == AssemblyQualifiedName)
                {
                    return false;
                }
            }


            HttpModuleAction hand = new HttpModuleAction(module.Name, AssemblyQualifiedName);
            sysweb.Modules.Add(hand);
            return true;
        }

        public static bool RegisterHttpHandler(Marbles.Core.Handlers.IHttpHandlerBase handler)
        {
            return RegisterHttpHandler1(handler, handler.Path, handler.Verbs, handler.Validate);
        }

        public static bool RegisterHttpHandler(Marbles.Core.Handlers.IHttpHandlerFactoryBase handler)
        {
            return RegisterHttpHandler1(handler, handler.Path, handler.Verbs, handler.Validate);
        }

        private static bool RegisterHttpHandler1(object handler, string path, string verbs, bool validate)
        {
            HttpHandlersSection sysweb = WebConfigurationManager.GetSection("system.web/httpHandlers") as HttpHandlersSection;

            string AssemblyQualifiedName = handler.GetType().AssemblyQualifiedName;

            for (int i = 0; i < sysweb.Handlers.Count; i++)
            {
                if (sysweb.Handlers[i].Type == AssemblyQualifiedName)
                {
                    return false;
                }
            }

            HttpHandlerAction hand = new HttpHandlerAction(path, AssemblyQualifiedName, verbs, validate);
            sysweb.Handlers.Add(hand);
            return true;
        }

        public static void RegisterHttpHandlers()
        {
            Assembly assm = typeof(SettingsManager).Assembly;

            foreach (Type t in assm.GetTypes())
            {
                Type iType = t.GetInterface("Marbles.Core.Handlers.IHttpHandlerBase", true);

                if (iType != null)
                {
                    IHttpHandlerBase item = Activator.CreateInstance(t) as IHttpHandlerBase;
                    RegisterHttpHandler(item);
                    continue;
                }

                iType = t.GetInterface("Marbles.Core.Handlers.IHttpHandlerFactoryBase", true);
                if (iType != null)
                {
                    IHttpHandlerFactoryBase item = Activator.CreateInstance(t) as IHttpHandlerFactoryBase;
                    RegisterHttpHandler(item);
                }


            }
        }

        public static void RegisterHttpModules()
        {
            Assembly assm = typeof(SettingsManager).Assembly;

            foreach (Type t in assm.GetTypes())
            {
                Type iType = t.GetInterface("Marbles.Core.Handlers.IHttpModuleBase", true);
                if (iType != null)
                {
                    IHttpModuleBase item = Activator.CreateInstance(t) as IHttpModuleBase;
                    RegisterHttpModule(item);
                }
            }
        }

        public static void WriteBaseConfiguration()
        {
            Assembly assm = typeof(SettingsManager).Assembly;

            StreamWriter sw = new StreamWriter(HttpContext.Current.Server.MapPath("~/web.config"));
            sw.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            sw.WriteLine("<configuration>");
            sw.WriteLine("    <connectionStrings>");
            sw.WriteLine("    </connectionStrings>");
            sw.WriteLine("    <appSettings>");
            sw.WriteLine("    </appSettings>");
            sw.WriteLine("    <system.net>");
            sw.WriteLine("        <mailSettings>");
            sw.WriteLine("        </mailSettings>");
            sw.WriteLine("    </system.net>");
            sw.WriteLine("    <system.web>");
            sw.WriteLine("        <httpHandlers>");
            sw.WriteLine("        </httpHandlers>");
            sw.WriteLine("        <httpModules>");
            sw.WriteLine("        </httpModules>");
            sw.WriteLine("    </system.web>");
            sw.WriteLine("    <system.webServer>");
            sw.WriteLine("        <validation validateIntegratedModeConfiguration=\"false\" />");
            sw.WriteLine("        <handlers>");

            foreach (Type t in assm.GetTypes())
            {
                Type iType = t.GetInterface("Marbles.Core.Handlers.IHttpHandlerBase", true);

                if (iType != null)
                {
                    IHttpHandlerBase item = Activator.CreateInstance(t) as IHttpHandlerBase;
                    sw.WriteLine(string.Format("<add name=\"{0}\" verb=\"{1}\" path=\"{2}\" type=\"{3}\" ></add>", item.Name, item.Verbs, item.Path, t.AssemblyQualifiedName));
                    continue;
                }

                iType = t.GetInterface("Marbles.Core.Handlers.IHttpHandlerFactoryBase", true);
                if (iType != null)
                {
                    IHttpHandlerFactoryBase item = Activator.CreateInstance(t) as IHttpHandlerFactoryBase;
                    sw.WriteLine(string.Format("<add name=\"{0}\" verb=\"{1}\" path=\"{2}\" type=\"{3}\" ></add>", item.Name, item.Verbs, item.Path, t.AssemblyQualifiedName));
                }
            }

            sw.WriteLine("        </handlers>");
            sw.WriteLine("        <modules>");

            foreach (Type t in assm.GetTypes())
            {
                Type iType = t.GetInterface("Marbles.Core.Handlers.IHttpModuleBase", true);
                if (iType != null)
                {
                    IHttpModuleBase item = Activator.CreateInstance(t) as IHttpModuleBase;
                    sw.WriteLine(string.Format("<add name=\"{0}\" type=\"{1}\" />", item.Name, t.AssemblyQualifiedName));
                }
            }

            sw.WriteLine("        </modules>");
            sw.WriteLine("    </system.webServer>");
            sw.WriteLine("</configuration>");
            sw.Flush();
            sw.Close();
        }

        public static bool RestartApplication()
        {
            try
            {
                HttpRuntime.UnloadAppDomain();
                return true;
            }
            catch
            {
            }

            string filename = HttpContext.Current.Server.MapPath(HttpContext.Current.Request.ApplicationPath + "/web.config");

            try
            {
                File.SetLastWriteTimeUtc(filename, DateTime.UtcNow);
                return true;
            }
            catch
            {
                return false;
            }
        }

        private static AspNetHostingPermissionLevel GetTrustLevel()
        {
            if (HttpContext.Current.Application["TrustLevel"] == null)
            {
                foreach (AspNetHostingPermissionLevel trustLevel in
                new AspNetHostingPermissionLevel[] {
                AspNetHostingPermissionLevel.Unrestricted,
                AspNetHostingPermissionLevel.High,
                AspNetHostingPermissionLevel.Medium,
                AspNetHostingPermissionLevel.Low,
                AspNetHostingPermissionLevel.Minimal 
            })
                {
                    try
                    {
                        new AspNetHostingPermission(trustLevel).Demand();
                    }
                    catch (System.Security.SecurityException)
                    {
                        continue;
                    }

                    HttpContext.Current.Application["TrustLevel"] = trustLevel;
                    return trustLevel;
                }

                HttpContext.Current.Application["TrustLevel"] = AspNetHostingPermissionLevel.Medium;
                return AspNetHostingPermissionLevel.Medium;
            }

            return (AspNetHostingPermissionLevel)HttpContext.Current.Application["TrustLevel"];
        }

        public static WebProxy CreateWebProxy()
        {
            try
            {
                return WebRequest.GetSystemWebProxy() as WebProxy;
            }
            catch
            {
                return null;
            }
            
        }
    }
}
